package com.letv.core.network.volley;

import com.letv.core.bean.DataHull;
import com.letv.core.bean.DataHull.DataType;
import com.letv.core.bean.LetvBaseBean;
import com.letv.core.config.LetvConfig;
import com.letv.core.network.volley.VolleyResponse.NetworkResponseState;
import com.letv.core.network.volley.VolleyResponse.ResponseSupplier;
import com.letv.core.network.volley.VolleyResult.VolleyNetworkResult;
import com.letv.core.network.volley.exception.DataIsErrException;
import com.letv.core.network.volley.exception.DataIsNullException;
import com.letv.core.network.volley.exception.DataNoUpdateException;
import com.letv.core.network.volley.exception.JsonCanNotParseException;
import com.letv.core.network.volley.exception.ParseException;
import com.letv.core.network.volley.exception.TokenLoseException;
import com.letv.core.network.volley.exception.VolleyException;
import com.letv.core.network.volley.listener.Network;
import com.letv.core.network.volley.listener.ResponseDelivery;
import com.letv.core.network.volley.listener.VolleyCache;
import com.letv.core.network.volley.toolbox.VolleyDbCache;
import com.letv.core.network.volley.toolbox.VolleyDiskCache;
import com.letv.core.utils.BaseTypeUtils;
import com.letv.core.utils.LetvLogApiTool;
import com.letv.core.utils.NetworkUtils;

/**
 * 网络请求数据
 * 
 * @author zhuqiao
 *
 */
public class NetworkRequestData<T extends LetvBaseBean> extends BaseRequestData<T> {
    private final Network mNetwork;

    /** 是否同步.如果是true,那么需要从回调中拿数据;else,直接返回数据 **/
    private final boolean mIsSync;

    public NetworkRequestData(ResponseDelivery delivery, Network network, boolean isSync) {
        super(ResponseSupplier.NETWORK, delivery);
        mNetwork = network;
        mIsSync = isSync;
    }

    /**
     * 开始请求
     * 
     * @param request
     * @param isSync 是否同步.如果是true,那么需要从回调中拿数据;else,直接返回数据
     * @return
     */
    public VolleyNetworkResult<T> start(VolleyRequest<T> request) {
        if (isCanceled(request)) {
            return mIsSync ? new VolleyNetworkResult<T>(null, request.mNetWorkDataHull, NetworkResponseState.IGNORE)
                    : null;
        }

        if (!isValidateSuccess(request)) {
            return mIsSync ? new VolleyNetworkResult<T>(null, request.mNetWorkDataHull, NetworkResponseState.PRE_FAIL)
                    : null;
        }

        VolleyResponse response;
        // 可能的错误
        NetworkResponseState possibleState;

        // 执行网络请求
        if (!NetworkUtils.isNetworkAvailable(request.mContext)) {
            response = new VolleyResponse(ResponseSupplier.NETWORK);
            possibleState = NetworkResponseState.NETWORK_NOT_AVAILABLE;
        } else {
            response = fetchResponseFromNetwork(request);
            possibleState = NetworkResponseState.NETWORK_ERROR;
        }

        if (!isResponseAvailabe(request, response)) {
            if (mIsSync) {
                return new VolleyNetworkResult<T>(null, request.mNetWorkDataHull, possibleState,
                        request.shouldPostErrorReport() ? request.getErrorInfo() : "");
            }

            if (request.isAlwaysCallbackNetworkResponse() || !request.isCacheSuccess()) {
                postError(request, possibleState);
            } else {
                request.finish();
            }
            return null;
        }

        // 解析
        return parseResponse(request, response);
    }

    /**
     * 从网络获取response
     * 
     * @param request
     * @return
     */
    private VolleyResponse fetchResponseFromNetwork(VolleyRequest<T> request) {
        if (request == null) {
            return new VolleyResponse(ResponseSupplier.NETWORK);
        }

        VolleyResponse response;
        long requestStartTime = 0;// 请求开始时间
        long requestEndTime = 0;// 请求结束时间

        try {
            requestStartTime = System.currentTimeMillis();
            response = mNetwork.performRequest(request);
            requestEndTime = System.currentTimeMillis();
        } catch (VolleyException e) {
            e.printStackTrace();
            response = new VolleyResponse(ResponseSupplier.NETWORK);
            request.setNeedPostErrorReport();
            // IOException
            logExpInfo(request, DataType.CONNECTION_FAIL, e);
        }

        // 设置错误信息统计,为了上报
        request.mNetWorkDataHull.addErrorInfo(0, request.getUrl());
        if (requestStartTime != 0 && requestEndTime != 0) {
            request.mNetWorkDataHull.addErrorInfo(2, "" + (requestEndTime - requestStartTime));
        } else {
            request.mNetWorkDataHull.addErrorInfo(2, "");
        }

        // 判断慢速比
        checkIsSlow(request);

        return response;
    }

    /**
     * 解析response
     * 
     * @param request
     * @param response
     */
    private VolleyNetworkResult<T> parseResponse(VolleyRequest<T> request, VolleyResponse response) {
        DataHull hull = request.mNetWorkDataHull;
        // 是否解析成功
        try {
            request.parse(response, ResponseSupplier.NETWORK);
            hull.setSourceData(response.data);
            if (request.getNetworkEntry() == null) {
                throw new DataIsErrException();
            }
            hull.setDataType(DataType.DATA_IS_INTEGRITY);
        } catch (ParseException e) {
            e.printStackTrace();
            logExpInfo(request, DataType.DATA_PARSE_EXCEPTION, e);
        } catch (DataIsNullException e) {
            e.printStackTrace();
            logExpInfo(request, DataType.DATA_IS_NULL, e);
        } catch (JsonCanNotParseException e) {
            e.printStackTrace();
            request.mNetWorkDataHull.setErrMsg(request.getErrCode());
            logExpInfo(request, DataType.DATA_CAN_NOT_PARSE, e);
        } catch (DataIsErrException e) {
            e.printStackTrace();
            logExpInfo(request, DataType.DATA_IS_ERR, e);
        } catch (DataNoUpdateException e) {
            e.printStackTrace();
            logExpInfo(request, DataType.DATA_NO_UPDATE, e);
        } catch (TokenLoseException e) {
            e.printStackTrace();
            hull.setDataType(DataType.TOKEN_LOSE);
        }

        request.mNetWorkDataHull.setMessage(request.getMessage());
        request.mNetWorkDataHull.setMarkId(request.getMarkId());
        return checkHullType(request, response);
    }

    /**
     * 验证dataType
     * 
     * @param request
     * @param response
     */
    private VolleyNetworkResult<T> checkHullType(VolleyRequest<T> request, VolleyResponse response) {
        int type = request.mNetWorkDataHull.getDataType();

        if (type == DataType.DATA_IS_INTEGRITY) {
            // ====== 容错:只有数据正确才会去做缓存! ======
            addNetworkDataToCache(request, response);
            if (!mIsSync) {
                postResponse(request);
            } else {
                return new VolleyNetworkResult<T>(request.getNetworkEntry(), request.mNetWorkDataHull,
                        NetworkResponseState.SUCCESS);
            }
        } else if (type == DataType.DATA_CAN_NOT_PARSE || type == DataType.DATA_PARSE_EXCEPTION
                || type == DataType.DATA_IS_ERR) {
            // 解析失败
            request.setNeedPostErrorReport();

            if (!mIsSync) {
                if (request.isAlwaysCallbackNetworkResponse() || !request.isCacheSuccess()) {
                    postError(request, NetworkResponseState.RESULT_ERROR);
                } else {
                    request.finish();
                }
            } else {
                return new VolleyNetworkResult<T>(null, request.mNetWorkDataHull, NetworkResponseState.RESULT_ERROR,
                        request.getErrorInfo());
            }
        } else if (type == DataType.DATA_NO_UPDATE) {
            // 数据无更新
            if (!mIsSync) {
                postError(request, NetworkResponseState.RESULT_NOT_UPDATE);
            } else {
                return new VolleyNetworkResult<T>(null, request.mNetWorkDataHull,
                        NetworkResponseState.RESULT_NOT_UPDATE);
            }
        } else {
            // 其他错误
            if (!mIsSync) {
                if (request.isAlwaysCallbackNetworkResponse() || !request.isCacheSuccess()) {
                    postError(request, NetworkResponseState.NETWORK_ERROR);
                } else {
                    request.finish();
                }
            } else {
                return new VolleyNetworkResult<T>(null, request.mNetWorkDataHull, NetworkResponseState.NETWORK_ERROR);
            }
        }

        return mIsSync ? new VolleyNetworkResult<T>(null, request.mNetWorkDataHull, NetworkResponseState.UNKONW) : null;
    }

    /**
     * 添加网络数据至缓存
     * 
     * @param request
     * @param response
     */
    @SuppressWarnings({ "unchecked", "rawtypes" })
    private void addNetworkDataToCache(VolleyRequest<T> request, VolleyResponse response) {
        if (request == null || response == null) {
            return;
        }

        VolleyCache<?> cache = request.getVolleyCache();
        if (cache instanceof VolleyDiskCache) {
            ((VolleyDiskCache) cache).add(request, response.data);
        } else if (cache instanceof VolleyDbCache) {
            ((VolleyDbCache) cache).add(request, request.getNetworkEntry());
        }
    }

    /**
     * 记录错误日志
     * 
     * @param request
     * @param dataType
     */
    private void logExpInfo(VolleyRequest<T> request, int dataType, Exception exception) {
        if (request == null || exception == null) {
            return;
        }

        DataHull hull = request.mNetWorkDataHull;
        hull.setDataType(dataType);

        LetvLogApiTool.createExceptionInfo(dataType, exception.getMessage(), request.getUrl(), hull.getSourceData());
    }

    /**
     * 判断请求速度是否比预期慢
     */
    private void checkIsSlow(VolleyRequest<T> request) {
        String timeStr = request.mNetWorkDataHull.getErrorInfo()[2];
        int requestTime = BaseTypeUtils.stoi(timeStr);
        int serverTime = (int) (LetvConfig.SLOW_TIME_OUT * 1000);

        if (requestTime > serverTime) {
            request.setNeedPostErrorReport();
        }
    }
}
